//将SDL函数和数据类型包含进来
#include "SDL/SDL.h"
#include <string>
#include <iostream>
#include <sstream>
#include "SDL/SDL_mixer.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_image.h"
#include "Timer.h"
#include "Dot.h"
#include "Cube.h"

using namespace std;

#define UNUSED(x) (void)x
//窗口属性
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//每秒的帧数
const int FRAMES_PER_SECOND = 30;

SDL_Surface *load_image( string filename ) 
{
    //临时的空间，用于存储刚刚加载好的图像
    SDL_Surface* loadedImage = NULL;
    //优化后的图像，实际使用的是这个图像
    SDL_Surface* optimizedImage = NULL;

    //加载图像
    loadedImage = IMG_Load( filename.c_str() );

    //如果加载图片没有出错
    if( loadedImage != NULL )
    {
        //创建一个优化了的图像
        optimizedImage = SDL_DisplayFormat( loadedImage );
        
        //释放临时的图像
        SDL_FreeSurface( loadedImage );
    }

    //如果图像优化成功
    if( optimizedImage != NULL )
    {
        //映射关键色 0x26ea21
        Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0x26, 0xea, 0x21 );
        //将所有颜色为（R 0, G 0xFF, B 0xFF）的像素设为透明。
        SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
    }

    //返回优化后的表面
    return optimizedImage;
}


/**
 * @brief 将原图片拷贝到指定位置
 * 
 * @param x : x轴偏移
 * @param y : y轴偏移
 * @param source : Blit的源图像
 * @param destination : 保存了Blit的目标图像
 * @param clip : 指定从图中获取图的位置
 */
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination , SDL_Rect* clip = NULL )
{
    //新建一个临时的矩形来保存偏移量
    SDL_Rect offset;
    
    //将传入的偏移量保存到矩形中
    offset.x = x;
    offset.y = y;
    //执行表面的Blit
    SDL_BlitSurface( source, clip, destination, &offset );
}

/**
 * @brief  设置窗口
 * 
 * @param screen : 初始化的界面
 * @return true  ： 成功
 * @return false  ： 失败
 */
bool initSDL(SDL_Surface **screen)
{
    //初始化SDL的所有子系统
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;
    }
    
    //初始化SDL_ttf
    if( TTF_Init() == -1 )
    {
        return false;    
    }
    

    //设置窗口
    *screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
    
    //如果设置出错
    if( *screen == NULL )
    {
        return false;    
    }

    
    //设置窗口标题
    SDL_WM_SetCaption( "TTF test", NULL );
    
    //如果所有初始化操作都成功
    return true;
}

/**
 * @brief 从文件中读取SDL_Surface
 * 
 * @param image : 保存从文件中读取的SDL_Surface
 * @param filename ： 需要读取的文件
 * @return true ： 读取成功
 * @return false ： 读取失败
 */
bool load_imageSurface( SDL_Surface **image, string filename )
{
    //加载图像
    *image = load_image( filename.c_str() );
    
    //如果加载出错
    if( *image == NULL )
    {
        return false;    
    }
    
    //如果所有图片加载正常
    return true;    
}


/**
 * @brief 释放load_imageSurface申请到的imageSDL_Surface
 * 
 * @param image : 需要释放的SDL_Surface
 */
void free_imageSurface( SDL_Surface *image )
{
    //释放图像
    SDL_FreeSurface( image ); 
}


bool load_OpenTTFFile( TTF_Font **font, string filename, int fontSize)
{
    //打开字体
    *font = TTF_OpenFont( filename.c_str(), fontSize );
    
    //如果字体加载出错
    if( *font == NULL )
    {
        return false;
    }
    
    //如果加载正常
    return true;    
}


void load_CloseTTFFile( TTF_Font *font)
{
    //关闭用过的字体
    TTF_CloseFont( font );  
}



int main( int argc, char* args[] ) 
{ 
    UNUSED(argc);
    UNUSED(args);
    //表面
    SDL_Surface *screen = NULL;
    SDL_Surface *dotBackground = NULL;
    SDL_Surface *cubeBackground = NULL;
    //将要用到的事件结构体
    SDL_Event event;
    //跟踪当前帧的帧计数器
    int frame = 0;
    //帧率调节器
    Timer fps;
    //新建计时器
    Timer update;
    //确保程序一直等待quit
    bool quit = false;
    //将要用到的字体
    TTF_Font *font = NULL;
    // //字体的颜色
    // SDL_Color textColor;
    // textColor.r = 255;
    // textColor.g = 0;
    // textColor.b = 255;
    //新建点
    Dot myDot1;
    Cube myCube;

    //初始化SDL
    if( initSDL(&screen) == false )
    {
        return 1;
    }
    
    //打开字体
    if( load_OpenTTFFile(&font, "/usr/share/fonts/opentype/noto/NotoSansCJK-Light.ttc", 40 ) == false )
    {
        cout << "load_OpenTTFFile: " << "NotoSansCJK-Light.ttc " << strerror(errno) <<endl;
    }

    //加载文件
    if( load_imageSurface(&dotBackground, "../assert/dot.bmp") == false )
    {
        return 1;    
    }

    //加载文件
    if( load_imageSurface(&cubeBackground, "../assert/cube.bmp") == false )
    {
        return 1;    
    }
    myDot1.setBackground(dotBackground);
    myCube.setBackground(cubeBackground);

    update.start();
    //当用户还不想退出时
    while( quit == false )
    {
        //启动帧计时器
        fps.start();

        //当有事件发生时，我们需要处理它们
        while( SDL_PollEvent( &event ) )
        {
            //处理圆点的事件
            myDot1.handle_input(event);
            myCube.handle_input1(event);
            //如果用户点击了窗口右上角的关闭按钮
            switch( event.type )
            {
                case SDL_QUIT:
                    //退出程序
                    quit = true;
                break;
            }
        }

        //移动圆点
        myDot1.move();
        myDot1.adaptPos(SCREEN_WIDTH, SCREEN_HEIGHT);
        myCube.move();
        myCube.adaptPos(SCREEN_WIDTH, SCREEN_HEIGHT);
        
        //用白色填充窗口
        SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );

        //将圆点显示在屏幕上
        myDot1.show(screen);
        myCube.show(screen);

        //更新窗口
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;    
        }
        
        //帧计数器加1
        frame++;

        //自从标题上次更新已经过了1秒
        if( update.get_ticks() > 1000 )
        {
            //以string形式表示的帧率
            std::stringstream caption;
            //计算帧率并创建string
            caption << "FPS: " << frame;
            //重置标题
            SDL_WM_SetCaption( caption.str().c_str(), NULL );
            //重启update计时器
            update.start(); 
            frame = 0;
        }

        //如果我们需要限制帧率
        if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
        {
            //休眠一段时间，时长为当前帧的剩余时间。
            SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
        }
    }

    //清理表面并退出SDL
    free_imageSurface(dotBackground);
    free_imageSurface(cubeBackground);

    //关闭字体
    load_CloseTTFFile(font);
    //退出SDL_ttf
    TTF_Quit();
    //退出SDL
    SDL_Quit();
    
    return 0;    
}